package jtalk.model;

import jtalk.controller.Properties;
import jtalk.logging.Logger;

import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;


public class XMPPManager extends AbstractModel {
		
	private XMPPConnection connection = null;
	private ConnectionListener connectionListener = null;
	private RosterStatusListener rosterStatusListener = null;
	private ChatEventListener chatEventListener;
	
	public XMPPManager() {
		this.connectionListener = new ConnectionStatusListener(this);	
		this.rosterStatusListener  = new RosterStatusListener(this);
		this.chatEventListener = new ChatEventListener(this);
	}
	
	/**
	 * 
	 * This set the host server and create the
	 * XMPPConnection instance.
	 * 
	 * @param server
	 */
	
	public void setServer(String server) {
						
		//The previous server
		String serverOldValue = null;
		
		//Test if a previous connection has been already set
		if(this.connection != null) {															
			serverOldValue = this.connection.getHost();
			//We disconnect old connection
			disconnect();															
		}								
		
		//Then create the new XMPPConnection		
		this.connection = new XMPPConnection(server);
						
		//then we try to connect ...		
		Logger.getLogger(this).info("Connecting to " + server);
		
		try {
									
			this.connection.connect();
			
			Logger.getLogger(this).info("Connected to " + connection.getHost());
			
			//We add the listeners
			Logger.getLogger(this).debug("Adding connection listener...");
			this.connection.addConnectionListener(this.connectionListener);			
			
		} catch (XMPPException e) {
			Logger.getLogger(this).error("Connection error : " + e.getMessage());
			e.printStackTrace();			
		}
						
		//We notify the new value to the controller
		firePropertyChange(Properties.SERVER.toString(), serverOldValue, this.connection.getHost());
											
		firePropertyChange(Properties.CONNECTED.toString(), null, this.connection.isConnected());						
		
	}

	public void disconnect() {
		//We disconnect the previous connection
		if(this.connection != null && this.connection.isConnected()) {
			Logger.getLogger(this).info("Disconect " + connection.getHost());
			this.connection.disconnect();
		}
	}
	
	public String getServer() {
		if(this.connection != null) {
			return this.connection.getHost();
		}else {
			return null;
		}		
	}
	
	public void login(String userName, String passwd) {
		if(this.connection != null) {			
			Logger.getLogger(this).info("Loggin in with UserName : " + userName);			
			try {				
				this.connection.login(userName, passwd);
				Logger.getLogger(this).info("User " + userName + " logged succesfully ...");
				
				//Add listeners
				Logger.getLogger(this).debug("Adding chat and roster listeners...");
				this.connection.getRoster().addRosterListener(this.rosterStatusListener);
				this.connection.getChatManager().addChatListener(this.chatEventListener);
				
			} catch (XMPPException e) {	
				Logger.getLogger(this).error("Loggin in has failed : " + e.getMessage());
				e.printStackTrace();
			}
			firePropertyChange(Properties.AUTHENTICATED.toString(), null, connection.isAuthenticated());							
		}else {
			Logger.getLogger(this).error("You do not have set the server yet (connection object is null)... Cannot loggin ...");
		}			
	}
	
	public boolean isConnected() {
		if(this.connection == null) {
			return false;
		}else{
			return this.connection.isConnected();
		}
	}
	
	public boolean isAuthenticated() {
		if(this.connection == null) {
			return false;
		}else{
			return this.connection.isAuthenticated();
		}
	}
	
	public void loadContactList() {
		
		if(this.connection != null) {
			
			Logger.getLogger(this).info("Loading contact list");
			
			Roster roster = this.connection.getRoster();
					
			for(RosterGroup group : roster.getGroups()) {
				for(RosterEntry contact : group.getEntries()) {
					
					Contact cct = new Contact(contact.getUser());
					cct.setGroup(group.getName());
					
					firePropertyChange(Properties.CONTACT_ADD.toString(), null, cct);				
				}
				
			}				

		}					
		
	}
	
	public void sendMessage(Message msg) {
		if(this.connection != null) {
			org.jivesoftware.smack.packet.Message message = new org.jivesoftware.smack.packet.Message();
			message.setType(org.jivesoftware.smack.packet.Message.Type.chat);
			message.setTo(msg.getTo().getName());			
			message.setFrom(this.connection.getUser());
			message.setBody(msg.getMessage());			
			connection.sendPacket(message);		
			Logger.getLogger(this).debug(msg + " body : " + msg.getMessage());
		}
	}

}
